bitkeeper revision 1.616.1.1 (3fbd0a530qmhBPZzzak7KZnyTNTggA)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 20 Nov 2003 18:39:15 +0000 (18:39 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 20 Nov 2003 18:39:15 +0000 (18:39 +0000)
Many files:
  Python wrapper module 'Xc' for libxc.
xc_py.c, setup.py, Makefile:
  new file

.rootkeys
tools/xc/Makefile
tools/xc/lib/libxc_domain.c
tools/xc/lib/libxc_linux_build.c
tools/xc/lib/libxc_misc.c
tools/xc/lib/libxc_vbd.c
tools/xc/lib/xc.h
tools/xc/py/Makefile [new file with mode: 0644]
tools/xc/py/setup.py [new file with mode: 0644]
tools/xc/py/xc_py.c [new file with mode: 0644]

index 5cdfe639edb54c6fb6b21e76621d14e75ab4c583..26dfc3af65cbac38976653310e1edca385f13690 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3fbba6dc38q-ioRlwSR_quw4G3qUeQ tools/xc/lib/libxc_vif.c
 3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/xc/lib/rpm.spec
 3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/xc/lib/xc.h
+3fbd0a3dTwnDcfdw0-v46dPbX98zDw tools/xc/py/Makefile
+3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py
+3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/xc/py/xc_py.c
 3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
 3f841450eJvqAD1Dldc0_aOweGiglQ xen/GUEST_CHANGES
 3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
index 81bd3944847d3ad18738ca288e50453bd536429f..29843adf140748b779876a07dfb3cde0161a0620 100644 (file)
@@ -1,9 +1,12 @@
 
 all:
        $(MAKE) -C lib
+       $(MAKE) -C py
 
 install:
        $(MAKE) -C lib install
+       $(MAKE) -C py  install
 
 clean:
-       $(MAKE) -C lib xlean
+       $(MAKE) -C lib clean
+       $(MAKE) -C py  clean
index 93881d17f1fb428694535b09a73ef5589109f643..9c60bd6acee80fa9e99ecfa809061fccac563895 100644 (file)
@@ -81,6 +81,7 @@ int xc_domain_getinfo(int xc_handle,
         info->name[XC_DOMINFO_MAXNAME-1] = '\0';
 
         next_domid = op.u.getdomaininfo.domain + 1;
+        info++;
     }
 
     return nr_doms;
index 08966c828369a82cfe737677912b2b1476ac1af1..e7acaa8c95ff6d66588d012cb9cabc4075835a2a 100644 (file)
@@ -317,11 +317,11 @@ static int setup_guestos(int xc_handle,
     return -1;
 }
 
-int xc_domain_build(int xc_handle,
-                    unsigned int domid,
-                    const char *image_name,
-                    const char *ramdisk_name,
-                    const char *cmdline)
+int xc_linux_build(int xc_handle,
+                   unsigned int domid,
+                   const char *image_name,
+                   const char *ramdisk_name,
+                   const char *cmdline)
 {
     dom0_op_t launch_op, op;
     unsigned long load_addr;
index 297f40fe0645b7dba8ac21bdd3112beb2d9f2aaf..a1fd45a19affd3dd4eebff07f6b5f9adfbc38cfd 100644 (file)
@@ -8,7 +8,10 @@
 
 int xc_interface_open(void)
 {
-    return open("/proc/xeno/privcmd", O_RDWR);
+    int fd = open("/proc/xeno/privcmd", O_RDWR);
+    if ( fd == -1 )
+        PERROR("Could not obtain handle on privileged command interface");
+    return fd;
 }
 
 int xc_interface_close(int xc_handle)
index 64e21f79e81d0173fe9fc802853c98bb04fd35d2..3f9e67c2b2fb9118d3c88535807e3ee8b202e5f9 100644 (file)
@@ -73,7 +73,6 @@ int xc_vbd_delete_extent(int xc_handle,
 
 int xc_vbd_probe(int xc_handle,
                  unsigned int domid,
-                 unsigned short vbdid,
                  unsigned int max_vbds,
                  xc_vbd_t *vbds)
 {
@@ -82,7 +81,7 @@ int xc_vbd_probe(int xc_handle,
     int i, j, ret, allocsz = max_vbds * sizeof(xen_disk_t); 
 
     op.cmd = BLOCK_IO_OP_VBD_PROBE; 
-    op.u.probe_params.domain    = domid; 
+    op.u.probe_params.domain = domid; 
     
     xdi->max   = max_vbds;
     xdi->disks = malloc(allocsz);
index ec8c483ffa74c7f6ae3c7ead170c723d2a06f044..6b025a1c8b9b1833c1f956c9c9c2f99ee8a9e5a5 100644 (file)
@@ -44,7 +44,8 @@ int xc_linux_save(int xc_handle,
                   const char *state_file, 
                   int verbose);
 int xc_linux_restore(int xc_handle,
-                     const char *state_file, int verbose);
+                     const char *state_file, 
+                     int verbose);
 int xc_linux_build(int xc_handle,
                    unsigned int domid,
                    const char *image_name,
@@ -114,7 +115,6 @@ int xc_vbd_delete_extent(int xc_handle,
                          unsigned long nr_sectors);
 int xc_vbd_probe(int xc_handle,
                  unsigned int domid,
-                 unsigned short vbdid,
                  unsigned int max_vbds,
                  xc_vbd_t *vbds);
 
diff --git a/tools/xc/py/Makefile b/tools/xc/py/Makefile
new file mode 100644 (file)
index 0000000..b6dcd8b
--- /dev/null
@@ -0,0 +1,9 @@
+
+all: ../lib/libxc.a
+       python setup.py build
+
+install:
+       # How to install Xc.so ??
+
+clean:
+       rm -rf build
diff --git a/tools/xc/py/setup.py b/tools/xc/py/setup.py
new file mode 100644 (file)
index 0000000..5909603
--- /dev/null
@@ -0,0 +1,16 @@
+
+from distutils.core import setup, Extension
+
+module = Extension("Xc",
+                   include_dirs         = ["../lib"],
+                   library_dirs         = ["../lib"],
+                   sources              = ["xc_py.c"])
+
+# Include the following line to link against shared libxc.so
+#module.libraries = ["xc"]
+
+# Include the following lines to link against static libxc.a
+module.extra_objects = ["../lib/libxc.a"]
+module.libraries     = ["z"]
+
+setup(name = "Xc", version = "1.0", ext_modules = [module])
diff --git a/tools/xc/py/xc_py.c b/tools/xc/py/xc_py.c
new file mode 100644 (file)
index 0000000..099f187
--- /dev/null
@@ -0,0 +1,704 @@
+/******************************************************************************
+ * xc_py.c
+ * 
+ * Copyright (c) 2003, K A Fraser
+ */
+
+#include <Python.h>
+#include <xc.h>
+
+typedef struct {
+    PyObject_HEAD;
+    int xc_handle;
+} XcObject;
+
+/*
+ * Definitions for the 'xc' object type.
+ */
+
+static PyObject *pyxc_domain_create(PyObject *self,
+                                    PyObject *args,
+                                    PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int mem_kb = 65536;
+    char        *name   = "(anon)";
+    int          ret;
+
+    static char *kwd_list[] = { "mem_kb", "name" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|is", kwd_list, 
+                                      &mem_kb, &name) )
+        return NULL;
+
+    ret = xc_domain_create(xc->xc_handle, mem_kb, name);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_domain_start(PyObject *self,
+                                   PyObject *args,
+                                   PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int dom;
+    int          ret;
+
+    static char *kwd_list[] = { "dom" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+        return NULL;
+
+    ret = xc_domain_start(xc->xc_handle, dom);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_domain_stop(PyObject *self,
+                                  PyObject *args,
+                                  PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int dom;
+    int          ret;
+
+    static char *kwd_list[] = { "dom" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+        return NULL;
+
+    ret = xc_domain_stop(xc->xc_handle, dom);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_domain_getinfo(PyObject *self,
+                                     PyObject *args,
+                                     PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+    PyObject *list;
+
+    unsigned int  first_dom = 0, max_doms = 1024;
+    int           nr_doms, i;
+    xc_dominfo_t *info;
+
+    static char *kwd_list[] = { "first_dom", "max_doms" };
+    
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list,
+                                      &first_dom, &max_doms) )
+        return NULL;
+
+    info = malloc(max_doms * sizeof(xc_dominfo_t));
+    if ( info == NULL )
+        nr_doms = 0;
+    else
+        nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info);
+    
+    list = PyList_New(nr_doms);
+    for ( i = 0 ; i < nr_doms; i++ )
+    {
+        PyList_SetItem(
+            list, i, 
+            Py_BuildValue("{s:i,s:i,s:i,s:i,s:l,s:L,s:s}",
+                          "dom",      info[i].domid,
+                          "cpu",      info[i].cpu,
+                          "running",  info[i].has_cpu,
+                          "stopped",  info[i].stopped,
+                          "mem_kb",   info[i].nr_pages*4,
+                          "cpu_time", info[i].cpu_time,
+                          "name",     info[i].name));
+    }
+
+    if ( info != NULL )
+        free(info);
+
+    return list;
+}
+
+static PyObject *pyxc_linux_save(PyObject *self,
+                                 PyObject *args,
+                                 PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int dom;
+    char        *state_file;
+    int          progress = 1, ret;
+
+    static char *kwd_list[] = { "dom", "state_file", "progress" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|i", kwd_list, 
+                                      &dom, &state_file, &progress) )
+        return NULL;
+
+    ret = xc_linux_save(xc->xc_handle, dom, state_file, progress);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_linux_restore(PyObject *self,
+                                    PyObject *args,
+                                    PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    char        *state_file;
+    int          progress = 1, ret;
+
+    static char *kwd_list[] = { "state_file", "progress" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwd_list, 
+                                      &state_file, &progress) )
+        return NULL;
+
+    ret = xc_linux_restore(xc->xc_handle, state_file, progress);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_linux_build(PyObject *self,
+                                  PyObject *args,
+                                  PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int dom;
+    char        *image, *ramdisk = NULL, *cmdline = "";
+    int          ret;
+
+    static char *kwd_list[] = { "dom", "image", "ramdisk", "cmdline" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|ss", kwd_list, 
+                                      &dom, &image, &ramdisk, &cmdline) )
+        return NULL;
+
+    ret = xc_linux_build(xc->xc_handle, dom, image, ramdisk, cmdline);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_bvtsched_global_set(PyObject *self,
+                                          PyObject *args,
+                                          PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned long ctx_allow;
+    int           ret;
+
+    static char *kwd_list[] = { "ctx_allow" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) )
+        return NULL;
+
+    ret = xc_bvtsched_global_set(xc->xc_handle, ctx_allow);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_bvtsched_domain_set(PyObject *self,
+                                          PyObject *args,
+                                          PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int  dom;
+    unsigned long mcuadv, warp, warpl, warpu;
+    int           ret;
+
+    static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl", "warpu" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illll", kwd_list, 
+                                      &dom, &mcuadv, &warp, &warpl, &warpu) )
+        return NULL;
+
+    ret = xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, 
+                                 warp, warpl, warpu);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_vif_scheduler_set(PyObject *self,
+                                        PyObject *args,
+                                        PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int  dom, vif;
+    xc_vif_sched_params_t sched = { 0, 0 };
+    int           ret;
+
+    static char *kwd_list[] = { "dom", "vif", "credit_bytes", "credit_usecs" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii|ll", kwd_list, 
+                                      &dom, &vif, 
+                                      &sched.credit_bytes, 
+                                      &sched.credit_usec) )
+        return NULL;
+
+    ret = xc_vif_scheduler_set(xc->xc_handle, dom, vif, &sched);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_vif_scheduler_get(PyObject *self,
+                                        PyObject *args,
+                                        PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+    PyObject *dict;
+
+    unsigned int  dom, vif;
+    xc_vif_sched_params_t sched;
+    int           ret;
+
+    static char *kwd_list[] = { "dom", "vif" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, 
+                                      &dom, &vif) )
+        return NULL;
+
+    ret = xc_vif_scheduler_get(xc->xc_handle, dom, vif, &sched);
+
+    if ( ret < 0 )
+        dict = Py_BuildValue("{}");
+    else
+        dict = Py_BuildValue("{s:l,s:l}", 
+                             "credit_bytes", sched.credit_bytes,
+                             "credit_usecs", sched.credit_usec);
+    
+    return dict;
+}
+
+static PyObject *pyxc_vif_stats_get(PyObject *self,
+                                    PyObject *args,
+                                    PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+    PyObject *dict;
+
+    unsigned int  dom, vif;
+    xc_vif_stats_t stats;
+    int           ret;
+
+    static char *kwd_list[] = { "dom", "vif" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, 
+                                      &dom, &vif) )
+        return NULL;
+
+    ret = xc_vif_stats_get(xc->xc_handle, dom, vif, &stats);
+
+    if ( ret < 0 )
+        dict = Py_BuildValue("{}");
+    else
+        dict = Py_BuildValue("{s:L,s:L,s:L,s:L}", 
+                             "tx_bytes", stats.tx_bytes,
+                             "tx_packets", stats.tx_pkts,
+                             "rx_bytes", stats.rx_bytes,
+                             "rx_packets", stats.rx_pkts);
+    
+    return dict;
+}
+
+static PyObject *pyxc_vbd_create(PyObject *self,
+                                 PyObject *args,
+                                 PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int dom, vbd;
+    int          writeable, ret;
+
+    static char *kwd_list[] = { "dom", "vbd", "writeable" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwd_list, 
+                                      &dom, &vbd, &writeable) )
+        return NULL;
+
+    ret = xc_vbd_create(xc->xc_handle, dom, vbd, writeable);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_vbd_destroy(PyObject *self,
+                                  PyObject *args,
+                                  PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int dom, vbd;
+    int          ret;
+
+    static char *kwd_list[] = { "dom", "vbd" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, 
+                                      &dom, &vbd) )
+        return NULL;
+
+    ret = xc_vbd_destroy(xc->xc_handle, dom, vbd);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_vbd_add_extent(PyObject *self,
+                                     PyObject *args,
+                                     PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int  dom, vbd, device;
+    unsigned long start_sector, nr_sectors;
+    int           ret;
+
+    static char *kwd_list[] = { "dom", "vbd", "device", 
+                                "start_sector", "nr_sectors" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiill", kwd_list, 
+                                      &dom, &vbd, &device, 
+                                      &start_sector, &nr_sectors) )
+        return NULL;
+
+    ret = xc_vbd_add_extent(xc->xc_handle, dom, vbd, device, 
+                            start_sector, nr_sectors);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_vbd_delete_extent(PyObject *self,
+                                        PyObject *args,
+                                        PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int  dom, vbd, device;
+    unsigned long start_sector, nr_sectors;
+    int           ret;
+
+    static char *kwd_list[] = { "dom", "vbd", "device", 
+                                "start_sector", "nr_sectors" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiill", kwd_list, 
+                                      &dom, &vbd, &device, 
+                                      &start_sector, &nr_sectors) )
+        return NULL;
+
+    ret = xc_vbd_delete_extent(xc->xc_handle, dom, vbd, device, 
+                               start_sector, nr_sectors);
+    
+    return PyInt_FromLong(ret);
+}
+
+static PyObject *pyxc_vbd_probe(PyObject *self,
+                                PyObject *args,
+                                PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+    PyObject *list;
+
+    unsigned int dom = XC_VBDDOM_PROBE_ALL, max_vbds = 1024;
+    xc_vbd_t    *info;
+    int          nr_vbds, i;
+
+    static char *kwd_list[] = { "dom", "max_vbds" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, 
+                                      &dom, &max_vbds) )
+        return NULL;
+
+    info = malloc(max_vbds * sizeof(xc_vbd_t));
+    if ( info == NULL )
+        nr_vbds = 0;
+    else
+        nr_vbds = xc_vbd_probe(xc->xc_handle, dom, max_vbds, info);
+
+    list = PyList_New(nr_vbds);
+    for ( i = 0; i < nr_vbds; i++ )
+    {
+        PyList_SetItem(
+            list, i, 
+            Py_BuildValue("{s:i,s:i,s:i,s:l}",
+                          "dom",        info[i].domid,
+                          "vbd",        info[i].vbdid,
+                          "writeable",  !!(info[i].flags & XC_VBDF_WRITEABLE),
+                          "nr_sectors", info[i].nr_sectors));
+    }
+
+    if ( info != NULL )
+        free(info);
+
+    return list;
+}
+
+static PyObject *pyxc_readconsolering(PyObject *self,
+                                      PyObject *args,
+                                      PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+    PyObject *pystr = Py_None;
+
+    unsigned int clear = 0;
+    char         str[32768];
+    int          ret;
+
+    static char *kwd_list[] = { "clear" };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) )
+        return NULL;
+
+    ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear);
+
+    if ( ret > 0 )
+        pystr = PyString_FromString(str);
+    
+    return pystr;
+}
+
+static PyMethodDef pyxc_methods[] = {
+    { "domain_create", 
+      (PyCFunction)pyxc_domain_create, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Create a new domain.\n"
+      " mem_kb [int, 65536]:    Memory allocation, in kilobytes.\n"
+      " name   [str, '(anon)']: Informative textual name.\n\n"
+      "Returns: [int] new domain identifier; -1 on error.\n" },
+
+    { "domain_start", 
+      (PyCFunction)pyxc_domain_start, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Start execution of a domain.\n"
+      " dom [int]: Identifier of domain to be started.\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "domain_stop", 
+      (PyCFunction)pyxc_domain_stop, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Stop execution of a domain.\n"
+      " dom [int]: Identifier of domain to be stopped.\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "domain_getinfo", 
+      (PyCFunction)pyxc_domain_getinfo, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Get information regarding a set of domains, in increasing id order.\n"
+      " first_dom [int, 0]:    First domain to retrieve info about.\n"
+      " max_doms  [int, 1024]: Maximum number of domains to retrieve info"
+      " about.\n\n"
+      "Returns: [list of dicts] if list length is less than 'max_doms'\n"
+      "         parameter then there was an error, or the end of the\n"
+      "         domain-id space was reached.\n"
+      " dom      [int]:  Identifier of domain to which this info pertains\n"
+      " cpu      [int]:  CPU to which this domain is bound\n"
+      " running  [int]:  Bool - is the domain currently running?\n"
+      " stopped  [int]:  Bool - is the domain suspended?\n"
+      " mem_kb   [int]:  Memory reservation, in kilobytes\n"
+      " cpu_time [long]: CPU time consumed, in nanoseconds\n"
+      " name     [str]:  Identifying name\n" },
+
+    { "linux_save", 
+      (PyCFunction)pyxc_linux_save, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Save the CPU and memory state of a Linux guest OS.\n"
+      " dom        [int]:    Identifier of domain to be saved.\n"
+      " state_file [str]:    Name of state file. Must not currently exist.\n"
+      " progress   [int, 1]: Bool - display a running progress indication?\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "linux_restore", 
+      (PyCFunction)pyxc_linux_restore, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Restore the CPU and memory state of a Linux guest OS.\n"
+      " state_file [str]:    Name of state file. Must not currently exist.\n"
+      " progress   [int, 1]: Bool - display a running progress indication?\n\n"
+      "Returns: [int] new domain identifier on success; -1 on error.\n" },
+
+    { "linux_build", 
+      (PyCFunction)pyxc_linux_build, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Build a new Linux guest OS.\n"
+      " dom     [int]:      Identifier of domain to build into.\n"
+      " image   [str]:      Name of kernel image file. May be gzipped.\n"
+      " ramdisk [str, n/a]: Name of ramdisk file, if any.\n"
+      " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
+      "Returns: [int] new domain identifier on success; -1 on error.\n" },
+
+    { "bvtsched_global_set", 
+      (PyCFunction)pyxc_bvtsched_global_set, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Set global tuning parameters for Borrowed Virtual Time scheduler.\n"
+      " ctx_allow [int]: Minimal guaranteed quantum (I think!).\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "bvtsched_domain_set", 
+      (PyCFunction)pyxc_bvtsched_domain_set, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Set per-domain tuning parameters for Borrowed Virtual Time scheduler.\n"
+      " dom    [int]: Identifier of domain to be tuned.\n"
+      " mcuadv [int]: Internal BVT parameter.\n"
+      " warp   [int]: Internal BVT parameter.\n"
+      " warpl  [int]: Internal BVT parameter.\n"
+      " warpu  [int]: Internal BVT parameter.\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "vif_scheduler_set", 
+      (PyCFunction)pyxc_vif_scheduler_set, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Set per-network-interface scheduling parameters.\n"
+      " dom          [int]:    Identifier of domain to be adjusted.\n"
+      " vif          [int]:    Identifier of VIF to be adjusted.\n"
+      " credit_bytes [int, 0]: Tx bytes permitted each interval.\n"
+      " credit_usecs [int, 0]: Interval, in usecs. 0 == no scheduling.\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "vif_scheduler_get", 
+      (PyCFunction)pyxc_vif_scheduler_get, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Query the per-network-interface scheduling parameters.\n"
+      " dom          [int]:    Identifier of domain to be queried.\n"
+      " vif          [int]:    Identifier of VIF to be queried.\n\n"
+      "Returns: [dict] dictionary is empty on failure.\n"
+      " credit_bytes [int]: Tx bytes permitted each interval.\n"
+      " credit_usecs [int]: Interval, in usecs. 0 == no scheduling.\n" },
+
+    { "vif_stats_get", 
+      (PyCFunction)pyxc_vif_stats_get, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Query the per-network-interface statistics.\n"
+      " dom          [int]: Identifier of domain to be queried.\n"
+      " vif          [int]: Identifier of VIF to be queried.\n\n"
+      "Returns: [dict] dictionary is empty on failure.\n"
+      " tx_bytes   [long]: Bytes transmitted.\n"
+      " tx_packets [long]: Packets transmitted.\n"
+      " rx_bytes   [long]: Bytes received.\n"
+      " rx_packets [long]: Packets received.\n" },
+
+    { "vbd_create", 
+      (PyCFunction)pyxc_vbd_create, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Create a new virtual block device associated with a given domain.\n"
+      " dom       [int]: Identifier of domain to get a new VBD.\n"
+      " vbd       [int]: Identifier for new VBD.\n"
+      " writeable [int]: Bool - is the new VBD writeable?\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "vbd_destroy", 
+      (PyCFunction)pyxc_vbd_destroy, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Destroy a virtual block device.\n"
+      " dom       [int]: Identifier of domain containing the VBD.\n"
+      " vbd       [int]: Identifier of the VBD.\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "vbd_add_extent", 
+      (PyCFunction)pyxc_vbd_add_extent, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Add an extent to a virtual block device.\n"
+      " dom          [int]: Identifier of domain containing the VBD.\n"
+      " vbd          [int]: Identifier of the VBD.\n"
+      " device       [int]: Identifier of the real underlying block device.\n"
+      " start_sector [int]: Real start sector of this extent.\n"
+      " nr_sectors   [int]: Length, in sectors, of this extent.\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "vbd_delete_extent", 
+      (PyCFunction)pyxc_vbd_delete_extent, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Delete an extent from a virtual block device.\n"
+      " dom          [int]: Identifier of domain containing the VBD.\n"
+      " vbd          [int]: Identifier of the VBD.\n"
+      " device       [int]: Identifier of the real underlying block device.\n"
+      " start_sector [int]: Real start sector of the extent.\n"
+      " nr_sectors   [int]: Length, in sectors, of the extent.\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "vbd_probe", 
+      (PyCFunction)pyxc_vbd_probe, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Get information regarding extant virtual block devices.\n"
+      " dom          [int, ALL]:  Domain to query (default is to query all).\n"
+      " max_vbds     [int, 1024]: Maximum VBDs to query.\n\n"
+      "Returns: [list of dicts] if list length is less than 'max_vbds'\n"
+      "         parameter then there was an error, or there were fewer vbds.\n"
+      " dom        [int]: Domain containing this VBD.\n"
+      " vbd        [int]: Domain-specific identifier of this VBD.\n"
+      " writeable  [int]: Bool - is this VBD writeable?\n"
+      " nr_sectors [int]: Size of this VBD, in 512-byte sectors.\n" },
+
+    { "readconsolering", 
+      (PyCFunction)pyxc_readconsolering, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Read Xen's console ring.\n"
+      " clear [int, 0]: Bool - clear the ring after reading from it?\n\n"
+      "Returns: [str] string is empty on failure.\n" },
+
+    { NULL, NULL, 0, NULL }
+};
+
+
+/*
+ * Definitions for the 'Xc' module wrapper.
+ */
+
+staticforward PyTypeObject PyXcType;
+
+static PyObject *PyXc_new(PyObject *self, PyObject *args)
+{
+    XcObject *xc;
+
+    if ( !PyArg_ParseTuple(args, ":new") )
+        return NULL;
+
+    xc = PyObject_New(XcObject, &PyXcType);
+
+    if ( (xc->xc_handle = xc_interface_open()) == -1 )
+    {
+        PyObject_Del((PyObject *)xc);
+        return NULL;
+    }
+
+    return (PyObject *)xc;
+}
+
+static PyObject *PyXc_getattr(PyObject *obj, char *name)
+{
+    return Py_FindMethod(pyxc_methods, obj, name);
+}
+
+static void PyXc_dealloc(PyObject *self)
+{
+    XcObject *xc = (XcObject *)self;
+    (void)xc_interface_close(xc->xc_handle);
+    PyObject_Del(self);
+}
+
+static PyTypeObject PyXcType = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,
+    "Xc",
+    sizeof(XcObject),
+    0,
+    PyXc_dealloc,    /* tp_dealloc     */
+    NULL,            /* tp_print       */
+    PyXc_getattr,    /* tp_getattr     */
+    NULL,            /* tp_setattr     */
+    NULL,            /* tp_compare     */
+    NULL,            /* tp_repr        */
+    NULL,            /* tp_as_number   */
+    NULL,            /* tp_as_sequence */
+    NULL,            /* tp_as_mapping  */
+    NULL             /* tp_hash        */
+};
+
+static PyMethodDef PyXc_methods[] = {
+    { "new", PyXc_new, METH_VARARGS, "Craate a new Xc object." },
+    { NULL, NULL, 0, NULL }
+};
+
+DL_EXPORT(void) initXc(void)
+{
+    Py_InitModule("Xc", PyXc_methods);
+}